package org.opens.javaskill.thread.threadLocal.apply;

import java.util.stream.IntStream;

/**
 * 功能:
 * <p>上下文设计模式</p>
 * 说明:
 * <pre>
 *     1. 使用ThreadLocal可以消灭传递参数.
 *     2. 由于这种设计模式使线程之间相互隔离, 推荐使用.
 * </pre>
 * @Date 2020/9/16 21:27
 * @Created by 99126
 */
public class ContextDesignPatternUseThreadLocal {

    public static void main(String[] args) {
        IntStream.rangeClosed(1, 5).forEach(i -> {
            new Thread(new ExecutionTask2()).start();
        });
    }

}

final class ActionContext {

    private static final ThreadLocal<Context2> threadLocal = new ThreadLocal<Context2>() {
        @Override
        protected Context2 initialValue() {
            return new Context2();
        }
    };

    private static class ContextHolder {
        private final static ActionContext actionContext = new ActionContext();
    }

    public static ActionContext getInstance() {
        return ContextHolder.actionContext;
    }

    public Context2 getContext() {
        return threadLocal.get();
    }

}

class Context2 {

    private String name;

    private String cardId;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

}

class ExecutionTask2 implements Runnable {

    // 模拟访问数据库
    private QueryAction2 queryAction = new QueryAction2();

    // 模拟从三方接口取数据
    private QueryFromHttpAction2 httpAction = new QueryFromHttpAction2();

    @Override
    public void run() {
        // 线程所持有的上下文
        queryAction.execute();
        httpAction.execute();

        showContextInfo();
    }

    public void showContextInfo() {
        ActionContext instance = ActionContext.getInstance();
        Context2 context = instance.getContext();

        System.out.println(context.getName() + " " + context.getCardId());
    }

}

class QueryAction2 {

    public void execute() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ActionContext instance = ActionContext.getInstance();
        Context2 context = instance.getContext();
        String name = "A";
        context.setName(name);
    }

}

class QueryFromHttpAction2 {

    public void execute() {
        ActionContext instance = ActionContext.getInstance();
        Context2 context = instance.getContext();
        String cardId = getCardIdByName(context.getName());
        context.setCardId(cardId);
    }

    public String getCardIdByName(String name) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String result = null;
        switch (name) {
            case "A":
                result = "1001";
                break;
            case "B":
                result = "1002";
                break;
            default:
                break;
        }
        return result;
    }

}